﻿/****************************************************************************
 * 工    具：  HK_UISystem
 
 * 描    述：  本UI框架旨在管理各种UI面板的打开、关闭及其层级、排序关系，
 *            本框架提供了一套机制，使得开发者可以方便地操控UI元素，确保界面层级按照预期显示，
 *            并且不同面板类型（全局面板和层级面板）能够和谐共存。
 *
 * 版    本：  V1.1
 * 作    者：  京产肠饭
 * 
 * 创    建：  2024/06/06  V1.0
 *
 * 更    新：  2025/04/11  V1.1
 *            1.Bug修复：重复 Hierarchy 层级面板重复开启的Bug，确保了当试图重复打开同一层级面板时，不会触发不必要的状态切换
 * 
 * 链    接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*****************************************************************************/

using QFramework;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace HKTools
{
    public enum HK_PanelType
    {
        GloblaType,    // 全局面板
        HierarchyType  // 层级面板
    }

    public interface IHK_UISystem : ISystem
    {
        /// <summary>
        /// 当前打开的 层级面板
        /// </summary>
        BindableProperty<HK_PanelName> CurrentHierarchyPanel { get; set; }

        /// <summary>
        /// 打开 指定面板
        /// </summary>
        void OpenAppointPanel(HK_PanelName panelName, string message = null);

        /// <summary>
        /// 关闭 指定面板
        /// </summary>
        void CloseGlobalPanel(HK_PanelName panelName);

        /// <summary>
        /// 关闭 层级面板
        /// </summary>
        void CloseHierarchyPanel();

        /// <summary>
        /// 是否打印Debug
        /// </summary>
        bool IsDebugOn { get; set; }
    }

    /// <summary>
    /// UI系统，负责管理UI面板的打开关闭，及其层级关系和排序。
    /// </summary>
    public class HK_UISystem : AbstractSystem, IHK_UISystem
    {
        public BindableProperty<HK_PanelName> CurrentHierarchyPanel { get; set; }

        public bool IsDebugOn { get; set; }

        Canvas curCanvas;

        RectTransform forDesign_RTF;
        RectTransform forShow_RTF;

        // 所有 Panel 的字典
        Dictionary<HK_PanelName, HK_PanelBase> allPanels_Dic;

        // 当前 开启的 全局面板
        HashSet<HK_PanelBase> globalPanels_HashSet;

        // 当前 加载的 层级面板
        Stack<HK_PanelBase> hierarchyPanels_Stack;

        HK_UIConfig config;

        protected override void OnInit()
        {
            try
            {
                curCanvas = GameObject.Find("UIRoot").GetComponent<Canvas>();
            }
            catch
            {
                HKDebug.LogWarning("UIRoot 查找失败！");
                return;
            }

            forDesign_RTF = curCanvas.transform.Find("ForDesign").GetComponent<RectTransform>();
            forShow_RTF = curCanvas.transform.Find("ForShow").GetComponent<RectTransform>();

            // 隐藏 ForDesign 下面的子物体
            for (int i = 0; i < forDesign_RTF.childCount; i++)
            {
                forDesign_RTF.GetChild(i).gameObject.SetActive(false);
            }

            config = Resources.Load<HK_UIConfig>("HK_UIConfig");

            allPanels_Dic = new Dictionary<HK_PanelName, HK_PanelBase>();
            globalPanels_HashSet = new HashSet<HK_PanelBase>();
            hierarchyPanels_Stack = new Stack<HK_PanelBase>();

            // UI系统初始化时，设置时候启用Debug，嫌烦的时候可以设为false关掉
            IsDebugOn = true;

            HKDebug.Log("IHK_UISystem 初始化完成!", LogColor.Cyan, LogStyle.Bold);
        }

        HK_PanelBase GetPanel(HK_PanelName panelName)
        {
            // 如果 字典中未查询到该Panel，则实例化一个
            if (!allPanels_Dic.TryGetValue(panelName, out var panel))
            {
                var panelItem = config.UIPanels.FirstOrDefault(item => item.PanelName.value == panelName);

                if (panelItem != null)
                {
                    panel = GameObject.Instantiate(panelItem.Panel, forShow_RTF);
                    panel.PanelType = panelItem.PanelType;
                    panel.PanelName.value = panelName;
                    panel.Order = panelItem.Order;

                    if (panel.name.Contains("Clone"))
                        panel.name = panel.name.Replace("(Clone)", "");

                    panel.Init();

                    allPanels_Dic.Add(panelName, panel);
                }
            }

            return panel;
        }

        public void OpenAppointPanel(HK_PanelName panelName, string message = null)
        {
            var panel = GetPanel(panelName);

            if (panel == null) return;

            switch (panel.PanelType)
            {
                case HK_PanelType.GloblaType:   // 如果是全局面板
                    if (globalPanels_HashSet.Add(panel))
                    {
                        panel.Open(message);
                    }
                    break;
                case HK_PanelType.HierarchyType:    // 如果是层级面板
                    if (CurrentHierarchyPanel == null)
                    {
                        CurrentHierarchyPanel = new BindableProperty<HK_PanelName>();
                    }
                    else
                    {
                        // 拦截 HierarchyPanel 重复打开请求
                        if (CurrentHierarchyPanel.Value == panelName)
                        {
                            return;
                        }
                    }

                    if (hierarchyPanels_Stack.Count > 0)
                    {
                        hierarchyPanels_Stack.Peek().Pause();
                    }

                    panel.Open(message);

                    hierarchyPanels_Stack.Push(panel);

                    CurrentHierarchyPanel.Value = panelName;

                    break;
            }

            // 打开一个新的Panel时，对所有面板重新进行排序
            var sortedPanels = allPanels_Dic.Values
                .OrderBy(item => item.Order)
                .ToList();

            for (int i = 0; i < sortedPanels.Count; i++)
            {
                sortedPanels[i].transform.SetSiblingIndex(i);
            }
        }

        // 根据 HK_PanelName 判定是不是全局面板
        public void CloseGlobalPanel(HK_PanelName panelName)
        {
            // 如果该Panel未打开
            if (allPanels_Dic.TryGetValue(panelName, out var curPanel))
            {
                // 不是全局面板，则返回
                if (globalPanels_HashSet.Remove(curPanel))
                {
                    curPanel.Close();
                }
                else
                {
                    Debug.LogWarning(panelName.ToString() + " 不是 GlobalPanel");
                }
            }
        }

        public void CloseHierarchyPanel()
        {
            if (hierarchyPanels_Stack.Count > 0)
            {
                hierarchyPanels_Stack.Pop().Close();
            }

            if (hierarchyPanels_Stack.Count > 0)
            {
                HK_PanelBase panel = hierarchyPanels_Stack.Peek();
                panel.Resume();
                CurrentHierarchyPanel.Value = panel.PanelName;
            }
        }
    }
}